<!DOCTYPE html>

<head>
    <meta charset="utf-8">

    <title>China Map</title>
    <script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<style>

    form {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        position: absolute;
        left: 10px;
        top: 10px;
    }

    label {
        display: block;
    }

</style>
<form>
    <label><input type="radio" name="mode" value="grouped"> Grouped</label>
    <label><input type="radio" name="mode" value="stacked" checked> Stacked</label>
</form>
<svg width="960" height="500"></svg>
<script>

    var n = 4, // The number of series.
        m = 58; // The number of values per series.

    // The xz array has m elements, representing the x-values shared by all series.
    // The yz array has n elements, representing the y-values of each of the n series.
    // Each yz[i] is an array of m non-negative numbers representing a y-value for xz[i].
    // The y01z array has the same structure as yz, but with stacked [y₀, y₁] instead of y.
    var xz = d3.range(m),
        yz = d3.range(n).map(function () {    //yz为平滑变化的非负数的数组..而且是包含四个数组的数组
            return bumps(m);
        }),
        y01z = d3.stack().keys(d3.range(n))(d3.transpose(yz)),
        yMax = d3.max(yz, function (y) {
            return d3.max(y);
        }),
        y1Max = d3.max(y01z, function (y) {
            return d3.max(y, function (d) {
                return d[1];
            });
        });
//
    console.log(xz);
//    console.log(y01z);


    //svg中的g的设置
    var svg = d3.select("svg"),
        margin = {top: 40, right: 10, bottom: 20, left: 10},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom,
        g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var x = d3.scaleBand()　　　//带band范围的scale（比例尺）
        .domain(xz)       //xz=[0-57]
        .rangeRound([0, width])
        .padding(0.08);          //padding的作用为确定padding在一个step中的比例，剩余部分为rangeband）
        //rangeBand + padding*step = step

    var y = d3.scaleLinear()　　　//线性尺度
        .domain([0, y1Max])
        .range([height, 0]);

    var color = d3.scaleOrdinal()   //颜色尺度  序数比例尺，定义域和值域都是离散的
        .domain(d3.range(n))
        .range(d3.schemeCategory20c);  //虽然它值域有20个颜色，但是因为domain的关系，只取了前四个

    var series = g.selectAll(".series")
        .data(y01z)
        .enter().append("g")
        .attr("fill", function (d, i) {
            return color(i);
        });

    var rect = series.selectAll("rect")
        .data(function (d) {
            return d;
        })
        .enter().append("rect")
        .attr("x", function (d, i) {
//            console.log(x(i));
            return x(i);       //设置ｘ坐标值
        })
        .attr("y", height)　　　//为什么这要设置height?
        .attr("width", x.bandwidth())　　　//
        .attr("height", 0);

    rect.transition()
        .delay(function (d, i) {
            return i * 10;　　　　　//根据ｉ使得靠后的矩形变化更慢
        })
        .attr("y", function (d) {
            return y(d[1]);
        })
        .attr("height", function (d) {
            return y(d[0]) - y(d[1]);
        });

    g.append("g")
        .attr("class", "axis axis--x")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x)
            .tickSize(0)
            .tickPadding(6));

    d3.selectAll("input")
        .on("change", changed);

    var timeout = d3.timeout(function () {
        d3.select("input[value=\"grouped\"]")
            .property("checked", true)
            .dispatch("change");
    }, 2000);

    function changed() {
        timeout.stop();
        if (this.value === "grouped") transitionGrouped();
        else transitionStacked();
    }

    function transitionGrouped() {
        y.domain([0, yMax]);

        rect.transition()
            .duration(500)
            .delay(function (d, i) {
                return i * 10;
            })
            .attr("x", function (d, i) {
                return x(i) + x.bandwidth() / n * this.parentNode.__data__.key;
            })
            .attr("width", x.bandwidth() / n)
            .transition()
            .attr("y", function (d) {
                return y(d[1] - d[0]);
            })
            .attr("height", function (d) {
                return y(0) - y(d[1] - d[0]);
            });
    }

    function transitionStacked() {
        y.domain([0, y1Max]);

        rect.transition()
            .duration(500)
            .delay(function (d, i) {
                return i * 10;
            })
            .attr("y", function (d) {
                return y(d[1]);
            })
            .attr("height", function (d) {
                return y(d[0]) - y(d[1]);
            })
            .transition()
            .attr("x", function (d, i) {
                return x(i);
            })
            .attr("width", x.bandwidth());
    }

    // Returns an array of m psuedorandom, smoothly-varying non-negative numbers.
    // Inspired by Lee Byron’s test data generator.
    // http://leebyron.com/streamgraph/
    //返回m个伪随机数的数组，平滑变化的非负数。
    function bumps(m) {
        var values = [], i, j, w, x, y, z;

        // Initialize with uniform random values in [0.1, 0.2).
        for (i = 0; i < m; ++i) {
            values[i] = 0.1 + 0.1 * Math.random();
        }

        // Add five random bumps.
        for (j = 0; j < 5; ++j) {
            x = 1 / (0.1 + Math.random());
            y = 2 * Math.random() - 0.5;
            z = 10 / (0.1 + Math.random());
            for (i = 0; i < m; i++) {
                w = (i / m - y) * z;
                values[i] += x * Math.exp(-w * w);
            }
        }

        // Ensure all values are positive.
        for (i = 0; i < m; ++i) {
            values[i] = Math.max(0, values[i]);
        }

        return values;
    }
</script>
</body>